<?php
/**
 * Eka Framework 0.3.0
 *
 * @copyright Copyright (c) 2008 Alexey Yu. Chuprina <656b61@gmail.com> (http://php-eka.googlecode.com)
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 *
 * @version $Id: Autoloader.php 40 2009-05-14 19:01:34Z 656b61 $
 */

/**
 * Eka_Autoloader
 *
 * @package Autoloader
 */
class Eka_Autoloader
{
	/**
	 * @var Eka_Autoloader
	 */
	static protected $instance;

	/**
	 * Singleton instance
	 *
	 * @return Eka_Autoloader
	 */
	static protected function getInstance()
	{
		if (!self::$instance) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Register autoload
	 *
	 * @param bool $callback
	 */
	static public function register($callback = null)
	{
		self::getInstance()->doRegister($callback);
	}

	/**
	 * Unregister autoload
	 *
	 * @param bool $callback
	 */
	static public function unregister($callback = null)
	{
		self::getInstance()->doUnregister($callback);
	}

	/**
	 * Load class by class name
	 *
	 * @param string $class Class name
	 */
	static public function load($class)
	{
		self::getInstance()->doLoad($class);
	}
	
	/**
	 * @return bool
	 */
	static public function isRegistered()
	{
		return self::getInstance()->registered();
	}

	############################################################################

	/**
	 * PHP file extention
	 *
	 * @var string
	 */
	protected $classFileExtention = 'php';

	/**
	 * Autoload registered flag
	 *
	 * @var bool
	 */
	protected $registered = false;
	
	protected $callbacks = array();
	
	/**
	 * Register autoload
	 *
	 * @param bool $callback
	 */
	protected function doRegister($callback = null)
	{
		if (null === $callback && $this->registered) {
			return;
		}
		
		if ($callback) {
			array_unshift($this->callbacks, $callback);
		}

		if (!$this->registered) {
			$functions = spl_autoload_functions();
			if (is_array($functions)) {
				foreach ($functions as $function) {
					spl_autoload_unregister($function);
				}
	
				array_unshift($functions, array($this, 'doLoad'));
	
				foreach ($functions as $function) {
					spl_autoload_register($function);
				}
	
			} else {
				spl_autoload_register(array($this, 'doLoad'));
			}
	
			$this->registered = true;
		}
	}

	/**
	 * Unregister autoload
	 *
	 * @param bool $callback
	 */
	protected function doUnregister($callback = null)
	{
		if (!$this->registered) {
			return;
		}
		if ($callback) {
			foreach ($this->callbacks as $key => $cb) {
				if ($cb === $callback) {
					unset($this->callbacks[$key]);
					break;
				}
			}
		} else {
			spl_autoload_unregister(array($this, 'load'));
			$this->registered = false;
		}
	}

	/**
	 * Load class by class name
	 *
	 * @param string $class Class name
	 */
	protected function doLoad($class)
	{
		if ($this->exists($class)) {
			return;
		}
		
		if (count($this->callbacks) > 0) {
			foreach ($this->callbacks as $callback) {
				call_user_func($callback, $class);
			}
			if ($this->exists($class)) {
				return;
			}
		}
		
		$path = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.' . $this->classFileExtention;
		foreach (explode(PATH_SEPARATOR, get_include_path()) as $includePath) {
			$file = $includePath . DIRECTORY_SEPARATOR . $path;
			if (file_exists($file)) {
				include_once $file;
				break;
			}
		}
	}
	
	protected function exists($class)
	{
		return class_exists($class, false) || interface_exists($class, false);
	}

	/**
	 * Force singleton
	 */
	protected function __construct()
	{}

	/**
	 * Force singleton
	 */
	protected function __clone()
	{}
}